package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zmj.sy.mom.srv.aps.bean.bo.ReverseFactoryCache;
import com.zmj.sy.mom.srv.aps.bean.bo.ReverseGroup;
import com.zmj.sy.mom.srv.aps.bean.bo.ReverseOrderCache;
import com.zmj.sy.mom.srv.aps.bean.bo.ReverseWorkCenter;
import com.zmj.sy.mom.srv.aps.bean.entity.base.BaseEntity;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.*;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseIdReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseListResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseSelectItemResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseSelectResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.reverseorder.*;
import com.zmj.sy.mom.srv.aps.config.ProjectConfig;
import com.zmj.sy.mom.srv.aps.config.StrategyConfig;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.MkBeanUtils;
import com.zmj.sy.mom.srv.aps.utils.PkgUtils;
import com.zmj.sy.mom.srv.aps.utils.SyExceptionUtils;
import com.zmj.sy.mom.srv.aps.utils.WorkshopProp;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
public class ReverseOrderService {

    private final ReverseOrderMapper reverseOrderMapper;

    private final OrderBomMapper orderBomMapper;

    private final OrderPhaseMapper orderPhaseMapper;

//    private final StationGroupMapper stationGroupMapper;

    private final GroupMapper groupMapper;

    private final OrderMapper orderMapper;

    private final StationMapper stationMapper;

    private final PhaseMapper phaseMapper;

    private final ReverseDetailMapper reverseDetailMapper;

    private final ApsOrderMapper apsOrderMapper;

    private final ProjectConfig projectConfig;

    private final CustomerMapper customerMapper;
    private final ObjectMapper jacksonObjectMapper;
    private final ReverseTopMapper reverseTopMapper;

    private final DictDataMapper dictDataMapper;
    private final StrategyConfig strategyConfig;
    private final ShiftMapper shiftMapper;
    private final ApsWorkOrderMapper apsWorkOrderMapper;
    private final ApsWorkDetailMapper apsWorkDetailMapper;
    private final ApsDetailWeekdayMapper apsDetailWeekdayMapper;
    private final FactoryMapper factoryMapper;

    public BaseListResVo<ReverseOrderListResVo> list(BaseIdReqVo reqVo) {

        Order order = orderMapper.selectById(reqVo.getId());

        LambdaQueryWrapper<ReverseOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ReverseOrder::getOrderId, reqVo.getId());
        wrapper.isNull(ReverseOrder::getParentId);
        List<ReverseOrder> list = reverseOrderMapper.selectList(wrapper);
        BaseListResVo<ReverseOrderListResVo> resVo = BaseListResVo.of(list, ReverseOrderListResVo.class);

        for (ReverseOrderListResVo datum : resVo.getData()) {
            datum.setOrderCode(order.getOrderCode());
            if (!StringUtils.hasText(datum.getOrderCode())) {
                datum.setOrderCode(order.getConstructNo());
            }
            datum.setMaterCode(order.getMaterCode());
            if (order.getOrderDateTime() != null) {
                datum.setOrderDate(order.getOrderDateTime().toLocalDate());
            }
        }

        return resVo;
    }

    @Transactional
    public Integer add(ReverseOrderAddReqVo reqVo, Map<String, DictData> groupBalancingRateMap) {
        Order order = orderMapper.selectById(reqVo.getOrderId());
        if (order == null) {
            throw SyExceptionUtils.e("没有找到该订单");
        }

        if (reqVo.getSplitNum() == null || reqVo.getSplitNum() <= 0) {
            throw SyExceptionUtils.e("拆分数量必须大于0");
        }

        if (reqVo.getSplitNum() > order.getOrderQty()) {
            throw SyExceptionUtils.e("拆包数不能大于订单数");
        }

        if (reqVo.getDeliveryDate() == null) {
            throw SyExceptionUtils.e("交付日期不能为空");
        }

        if (order.getOrderStatus().equals(1)) {
            order.setOrderStatus(2);
            orderMapper.updateById(order);
        }

        LambdaQueryWrapper<ReverseOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ReverseOrder::getOrderId, reqVo.getOrderId());
        wrapper.eq(ReverseOrder::getSplitNum, reqVo.getSplitNum());
        wrapper.isNull(ReverseOrder::getParentId);
        ReverseOrder currentReverseOrder = reverseOrderMapper.selectOne(wrapper);
        if (currentReverseOrder != null) {
            throw SyExceptionUtils.e("该订单已经拆分过了");
        }


        int div = order.getOrderQty() / reqVo.getSplitNum();
        int mod = order.getOrderQty() % reqVo.getSplitNum();
        if(mod > 0){
            div++;
        }

        int splitNum = order.getOrderQty() / div;
        if(order.getOrderQty() % div > 0){
            splitNum++;
        }


        ReverseOrder root = new ReverseOrder();
        root.setOrderId(reqVo.getOrderId());
        root.setSplitNum(splitNum);
        root.setDeliveryDate(reqVo.getDeliveryDate());
        root.setOrderQty(order.getOrderQty());
        root.setMoveFlag(1);
        root.setOrderCode(order.getOrderCode());
        reverseOrderMapper.insert(root);


        List<ReverseOrder> children = new ArrayList<>();
        for (int i = 0; i < splitNum; i++) {
            ReverseOrder orderSplit1 = new ReverseOrder();
            orderSplit1.setOrderId(reqVo.getOrderId());
            orderSplit1.setParentId(root.getId());
            orderSplit1.setSplitNum(i + 1);
            int currentQty = div;
            if (mod > 0 && i == (splitNum - 1)) {
                currentQty = order.getOrderQty() % div;
            }
            orderSplit1.setOrderQty(currentQty);
            orderSplit1.setDeliveryDate(reqVo.getDeliveryDate().minusDays(splitNum).plusDays(i));
            orderSplit1.setMoveFlag(1);
            children.add(orderSplit1);
        }

        reverseOrderMapper.insertBatchSomeColumn(children);

        // 倒序排产
        reverseAllScheduling(order, root, children, groupBalancingRateMap);

        root.setPlanStartDateTime(children.stream().min(Comparator.comparing(ReverseOrder::getPlanStartDateTime)).orElseGet(ReverseOrder::new).getPlanStartDateTime());
        root.setPlanEndDateTime(children.stream().max(Comparator.comparing(ReverseOrder::getPlanEndDateTime)).orElseGet(ReverseOrder::new).getPlanEndDateTime());
        reverseOrderMapper.updateById(root);


        return root.getId();
    }

    public void reverseAllScheduling(Order order, ReverseOrder root, List<ReverseOrder> children, Map<String, DictData> groupBalancingRateMap) {

        // 构建缓存数据
        ReverseFactoryCache factoryCache = createFactoryCache(order);

        // 对每个分包进行排产
        for (ReverseOrder child : children) {
            ReverseOrderCache orderCache = createOrderCache(order, root, child);
            List<ReverseDetail> reverseDetails = reverseAllScheduling(factoryCache, orderCache, groupBalancingRateMap);

            // 把分钟按天分隔
            List<ReverseDetail> dayDetails = dayDetails(child, reverseDetails);
            reverseDetailMapper.insertBatchSomeColumn(dayDetails);

            child.setPlanEndDateTime(dayDetails.stream().max(Comparator.comparing(ReverseDetail::getReverseStartTime)).orElseGet(ReverseDetail::new).getReverseStartTime());
            child.setPlanStartDateTime(dayDetails.stream().min(Comparator.comparing(ReverseDetail::getReverseEndTime)).orElseGet(ReverseDetail::new).getReverseEndTime());
            reverseOrderMapper.updateById(child);
        }

    }

    public List<ReverseDetail> dayDetails(ReverseOrder reverseOrder, List<ReverseDetail> reverseDetails) {


        List<ReverseDetail> l = new ArrayList<>();
        int daySecond = projectConfig.getDaySecond();
        LocalDate endDate = reverseOrder.getDeliveryDate();

        for (ReverseDetail reverseDetail : reverseDetails) {
            int timeRemaining = reverseDetail.getProcessSecond();
            //开始时间的偏移量
            int startSecond = reverseDetail.getPlanStartSecond() % daySecond;

            if(timeRemaining == 0){
                int dayMi = daySecond - startSecond; //剩余多少秒
                int kkk = dayMi;  // 实际使用的秒数

                if (timeRemaining <= dayMi) {
                    kkk = timeRemaining;
                }

                ReverseDetail rd = new ReverseDetail();
                MkBeanUtils.copyPropertiesIgnore(reverseDetail, rd);

                LocalDate localDate = endDate.minusDays((reverseDetail.getPlanStartSecond() / daySecond));
                rd.setReverseStartTime(LocalDateTime.of(localDate, LocalTime.of(23, 59, 59)).minusSeconds(startSecond));
                rd.setReverseEndTime(rd.getReverseStartTime().minusSeconds(kkk));
                rd.setReverseDay(localDate);
                rd.setReverseDaySecond(kkk);
                l.add(rd);
                continue;
            }

            List<ReverseDetail> temp = new ArrayList<>();
            for (int i = 0; timeRemaining > 0; i++) {
                int dayMi = daySecond - startSecond; //剩余多少秒
                int kkk = dayMi;  // 实际使用的秒数

                if (timeRemaining > dayMi) {
                    timeRemaining = timeRemaining - dayMi;

                } else {
                    kkk = timeRemaining;
                    timeRemaining = 0;
                }

                ReverseDetail rd = new ReverseDetail();
                MkBeanUtils.copyPropertiesIgnore(reverseDetail, rd);

                LocalDate localDate = endDate.minusDays(i + (reverseDetail.getPlanStartSecond() / daySecond));
                rd.setReverseStartTime(LocalDateTime.of(localDate, LocalTime.of(23, 59, 59)).minusSeconds(startSecond));
                rd.setReverseEndTime(rd.getReverseStartTime().minusSeconds(kkk));
                rd.setReverseDay(localDate);
                rd.setReverseDaySecond(kkk);
                if (i == 0) {
                    startSecond = 0;
                }
                temp.add(rd);
            }

            l.addAll(temp);
        }
        return l;
    }

    private ReverseOrderCache createOrderCache(Order order, ReverseOrder rootReverseOrder, ReverseOrder reverseOrder) {

        ReverseOrderCache orderCache = new ReverseOrderCache();

        orderCache.setOrder(order);
        orderCache.setRootReverseOrder(rootReverseOrder);
        orderCache.setReverseOrder(reverseOrder);

        // 填充所有物料
        List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().eq(OrderBom::getOrderId, order.getId()).list();
        orderCache.setOrderBomList(orderBomList);

        // 填充所有工序
        List<OrderPhase> orderPhaseList = orderPhaseMapper.lambdaQuery().eq(OrderPhase::getOrderId, order.getId()).list();
        orderCache.setOrderPhaseList(orderPhaseList);

        return orderCache;
    }

    private List<ReverseDetail> reverseAllScheduling(ReverseFactoryCache factoryCache, ReverseOrderCache orderCache, Map<String, DictData> groupBalancingRateMap) {
        DictData dictData = new DictData();
        dictData.setDictValue("1");


        orderCache.getOrderBomList().sort(Comparator.comparing(OrderBom::getLevel));
        List<OrderBom> orderBomList = orderCache.getOrderBomList();

        Map<Integer, OrderBom> orderBomIdMap = orderBomList.stream().collect(Collectors.toMap(OrderBom::getId, Function.identity()));
        for (OrderPhase orderPhase : orderCache.getOrderPhaseList()) {
            if (orderPhase.getPhaseSeq() == null) {
                throw SyExceptionUtils.e("没有配置工序顺序");
            }

            if(!StringUtils.hasText(orderPhase.getWorkGroupNumber())){
                throw SyExceptionUtils.e(orderPhase.getMaterName() + "没有配置工作组");
            }

            if(orderPhase.getWorkTime() == null){
                throw SyExceptionUtils.e(orderPhase.getMaterName() + "没有配置工时");
            }
        }

        Map<Integer, List<OrderPhase>> bomIdPhaseMap = orderCache.getOrderPhaseList()
                .stream()
                .sorted(Comparator.comparing(OrderPhase::getPhaseSeq))
                .collect(Collectors.groupingBy(OrderPhase::getBomId));

        Map<Integer, Map<Integer, ReverseDetail>> bomIdPhaseSeqMap = new LinkedHashMap<>();

        for (OrderBom orderBom : orderBomList) {
            List<OrderPhase> orderPhaseList = bomIdPhaseMap.get(orderBom.getId());
            if (orderPhaseList == null || orderPhaseList.isEmpty()) {
                continue;
            }

            // 反向计算工序时间
            int startSecond = 0;
            for (int i = orderPhaseList.size() - 1; i >= 0; i--) {
                // 是否是最开始的工序
                if (i == orderPhaseList.size() - 1) {
                    // 取父节点的
                    OrderBom parentBom = orderBomIdMap.get(orderBom.getPid());
                    if (parentBom != null) {
                        Map<Integer, ReverseDetail> map = bomIdPhaseSeqMap.get(parentBom.getId());

                        if (CollUtil.isEmpty(map)) {
                            throw SyExceptionUtils.e("零件[{}], 物料号[{}]没有找到父节点零件[{}], 物料号[{}]的工序", orderBom.getMaterName(), orderBom.getMaterCode(), parentBom.getMaterName(), parentBom.getMaterCode());
                        }

                        ReverseDetail reversePhase = map.get(1);
                        startSecond = reversePhase.getPlanEndSecond();
                    }

                } else {
                    // 取前一道工序
                    ReverseDetail reversePhase = bomIdPhaseSeqMap.get(orderPhaseList.get(i).getBomId()).get(orderPhaseList.get(i).getPhaseSeq() + 1);
                    startSecond = reversePhase.getPlanEndSecond();
                }

                ReverseDetail phase = new ReverseDetail();
                phase.setPhaseSeq(orderPhaseList.get(i).getPhaseSeq());
                phase.setPhaseId(orderPhaseList.get(i).getId());
                phase.setReverseOrderId(orderCache.getReverseOrder().getId());
                phase.setOrderId(orderCache.getReverseOrder().getOrderId());
                phase.setBomId(orderBom.getId());
                phase.setBomPid(orderBom.getPid());
                phase.setGroupCode(orderPhaseList.get(i).getWorkGroupNumber());
                phase.setPlanStartSecond(startSecond);
                phase.setLevel(orderBom.getLevel());

                bomIdPhaseSeqMap.computeIfAbsent(orderPhaseList.get(i).getBomId(), k -> new LinkedHashMap<>()).put(phase.getPhaseSeq(), phase);

                ReverseWorkCenter stationList = factoryCache.getWorkCenterMap().get(orderPhaseList.get(i).getWorkGroupNumber());
                if (stationList == null) {
                    throw SyExceptionUtils.e("零件[{}], 物料号[{}]没有找到工作组[{}],或者该工作组下没有工位", orderBom.getMaterName(), orderBom.getMaterCode(), orderPhaseList.get(i).getWorkGroupNumber());
                }

                phase.setStationGroupId(stationList.getStationGroupId());

                phase.setGroupId(stationList.getGroupId());

                // 取出这个工序的真实的工作秒数
                phase.setWorkCount(stationList.getGroupList().size());
                phase.setWorkAbility(stationList.getWorkAbility());
                phase.setWorkTime(orderPhaseList.get(i).getWorkTime());
                phase.setTotalCount(orderBomIdMap.get(orderBom.getId()).getTotalCount());

                phase.setSplitNum(orderCache.getReverseOrder().getSplitNum());

                int phaseTime = phase.getTotalCount()
                        .multiply(new BigDecimal(phase.getWorkTime()))//600
                        .multiply(new BigDecimal(groupBalancingRateMap.getOrDefault(phase.getGroupCode(), dictData).getDictValue())) //1
                        .divide(phase.getWorkAbility(), 5, RoundingMode.UP)// 1
                        .setScale(0, RoundingMode.UP)
                        .intValue();

                phase.setProcessSecond(phaseTime);

                phase.setPlanEndSecond(phase.getPlanStartSecond() + phase.getProcessSecond());

            }

        }

        /*


        Map<Integer, OrderBom> orderBomIdMap = orderBomList.stream().collect(Collectors.toMap(OrderBom::getId, Function.identity()));
        Map<Integer, Map<Integer, ReverseDetail>> bomIdPhaseSeqMap = new LinkedHashMap<>();
        Map<String, List<Station>> groupNumberStationMap = new HashMap<>();
//        Map<String, Group> myCodeGroupMap = factoryCache.getGroupList().stream().collect(Collectors.toMap(Group::getMyCode, Function.identity()));
        if (!factoryCache.getGroupList().isEmpty()) {
            List<Group> groupList = factoryCache.getGroupList();
            Map<Integer, List<StationGroup>> stationGroupMap = factoryCache.getStationGroupList().stream().filter(e -> e.getDefaultGroup().equals(1)).collect(Collectors.groupingBy(StationGroup::getGroupId));
            Map<Integer, Station> stationMap = factoryCache.getStationList().stream().collect(Collectors.toMap(Station::getId, Function.identity()));
            for (Group group : groupList) {
                List<StationGroup> stationGroups = stationGroupMap.get(group.getId());
                if (stationGroups == null || stationGroups.isEmpty()) {
                    continue;
                }

                List<Station> stations = stationGroups.stream().map(e -> stationMap.get(e.getStationId())).collect(Collectors.toList());
                groupNumberStationMap.put(group.getMyCode(), stations);
            }
        }

        // 排序后的每个零件

        return bomIdPhaseSeqMap.values().stream().flatMap(entry -> entry.values().stream()).sorted(Comparator.comparing(ReverseDetail::getPlanStartSecond)).collect(Collectors.toList());

         */

        return bomIdPhaseSeqMap.values().stream().flatMap(entry -> entry.values().stream()).sorted(Comparator.comparing(ReverseDetail::getPlanStartSecond)).collect(Collectors.toList());
    }

    public ReverseFactoryCache createFactoryCache(Order order) {
        ReverseFactoryCache cache = new ReverseFactoryCache();

        // 查询所有的组
        List<Group> groupList = groupMapper.selectList(Wrappers.<Group>lambdaQuery().eq(Group::getType, 2));
        cache.setGroupList(groupList);

        // 查询所有的工作组
//        List<StationGroup> stationGroupList = stationGroupMapper.selectList(null);
//        cache.setStationGroupList(stationGroupList);

        // 查询所有工位
        List<Station> stationList = stationMapper.selectList(null);
        cache.setStationList(stationList);

        // 取出所有工位的工作能力
        List<ReverseGroup> groupRefList = stationMapper.selectAll();
        Map<String, List<ReverseGroup>> collect = groupRefList.stream().collect(Collectors.groupingBy(ReverseGroup::getGroupCode));

        cache.setWorkCenterMap(new HashMap<>());
        for (Map.Entry<String, List<ReverseGroup>> entry : collect.entrySet()) {
            List<ReverseGroup> reverseGroups = entry.getValue();
            if (reverseGroups == null || reverseGroups.isEmpty()) {
                continue;
            }

            ReverseWorkCenter center = new ReverseWorkCenter();
            center.setGroupList(reverseGroups);
            center.setStationGroupId(reverseGroups.get(0).getId());
            center.setGroupId(reverseGroups.get(0).getGroupId());
            center.setWorkAbility(reverseGroups.stream()
                    .map(ReverseGroup::getWorkAbility)
                    .max(BigDecimal::compareTo)
                    .orElse(new BigDecimal(1)));
            cache.getWorkCenterMap().put(entry.getKey(), center);
        }

        // 排除工序
//        cache.setExcludePhase(Collections.singletonList(WorkshopProp.ycPhaseCode));


        return cache;
    }

    /**
     * @param reqVo
     * @param type  1是读缓存 2是初始化并写入缓存
     * @param order
     * @return
     * @throws JsonProcessingException
     */
    @SneakyThrows
    public ReverseOrderLoadsResVo loads(ReverseOrderLoadsReqVo reqVo, int type, Order order) {
        List<ReverseOrder> reverseOrderList = reverseOrderMapper.selectList(Wrappers.<ReverseOrder>lambdaQuery().eq(ReverseOrder::getParentId, reqVo.getId()));
        if(order.getLineId() == null){
            Factory line = factoryMapper.lambdaQuery().eq(Factory::getType, 2).eq(Factory::getMyCode, WorkshopProp.DEFAULT_LINE_CODE).one();
            if(line == null){
                throw SyExceptionUtils.e("请配置默认产线");
            }
            order.setLineId(line.getId());
            orderMapper.updateById(order);
        }
        Factory line = factoryMapper.selectById(order.getLineId());

        List<Integer> reverseOrderIds = reverseOrderList.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<ReverseDetail> reverseDetailList = reverseDetailMapper.selectList(Wrappers.<ReverseDetail>lambdaQuery().in(ReverseDetail::getReverseOrderId, reverseOrderIds));

        Integer daySecond = projectConfig.getDaySecond();
        Map<Integer, ReverseOrder> reverseOrderMap = reverseOrderList.stream().collect(Collectors.toMap(ReverseOrder::getId, Function.identity()));

        for (ReverseDetail reverseDetail : reverseDetailList) {
            Integer orderQty = reverseOrderMap.get(reverseDetail.getReverseOrderId()).getOrderQty();
            reverseDetail.setReverseDaySecond(reverseDetail.getReverseDaySecond() * orderQty);
        }

        List<Group> groups = groupMapper.lambdaQuery().eq(Group::getType, 2).eq(Group::getLineId, order.getLineId()).list();
        Map<String, Group> groupMap = groups.stream().collect(Collectors.toMap(Group::getMyCode, Function.identity(), (e1, e2) -> e1));
        List<Integer> groupIds = groups.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<Station> stations = stationMapper.lambdaQuery().in(Station::getGroupId, groupIds).list();
        Map<Integer, Long> stationGroupCountMap = stations.stream().collect(Collectors.groupingBy(Station::getGroupId, Collectors.counting()));

        List<ReverseDetail> reverseDetailList1 = reverseDetailList.stream().filter(e -> e.getGroupCode().equals("2-2_SC_ZHJT_02")).sorted(Comparator.comparing(ReverseDetail::getPhaseId)).collect(Collectors.toList());

        List<ReverseOrderLoadsDayResVo> data = reverseDetailList.stream().collect(
                        Collectors.groupingBy(
                                ReverseDetail::getReverseDay,
                                Collectors.groupingBy(
                                        ReverseDetail::getGroupCode, Collectors.summingInt(ReverseDetail::getReverseDaySecond)
                                )
                        )
                )
                .entrySet().stream().flatMap(e ->
                        e.getValue()
                                .entrySet()
                                .stream()
                                .map(ee -> {
                                    ReverseOrderLoadsDayResVo r = new ReverseOrderLoadsDayResVo();
                                    r.setWorkDay(e.getKey());
                                    r.setGroupNo(ee.getKey());
                                    if (groupMap.get(ee.getKey()) != null) {
                                        r.setGroupName(groupMap.get(ee.getKey()).getName());
                                    }

                                    if(groupMap.get(ee.getKey()) == null){
                                        throw SyExceptionUtils.e("产线【{}】没有找到工作组[{}],请检查工作组是否配置正确", line.getName(), ee.getKey());
                                    }
                                    Long l = stationGroupCountMap.get(groupMap.get(ee.getKey()).getId());
                                    if(l == null){
                                        throw SyExceptionUtils.e("产线【{}】没有找到工作组[{}]下的工位,请检查工位是否配置正确", line.getName(), ee.getKey());
                                    }

                                    r.setWorkLoad(new BigDecimal(ee.getValue())
                                            .divide(new BigDecimal(daySecond), 5, RoundingMode.HALF_UP)
                                            .divide(new BigDecimal(l), 4, RoundingMode.HALF_UP));
                                    return r;
                                })
                                .sorted(Comparator.comparing(ReverseOrderLoadsDayResVo::getWorkLoad).reversed())
                                .limit(10)
                ).collect(Collectors.toList());


        ReverseOrderLoadsResVo resVo = new ReverseOrderLoadsResVo();
        resVo.setData(data);

        if (type == 1) {

            ReverseTop top = reverseTopMapper.selectOne(Wrappers.<ReverseTop>lambdaQuery().eq(ReverseTop::getOrderId, reqVo.getId()));
            List<ReverseOrderLoadsDayResVo> reverseOrderLoadsDayResVos = new ArrayList<>();
            if (top != null) {
                reverseOrderLoadsDayResVos = jacksonObjectMapper.readValue(top.getTopStr(), new TypeReference<ArrayList<ReverseOrderLoadsDayResVo>>() {
                });
            }
            resVo.setTopTen(reverseOrderLoadsDayResVos);

        } else if (type == 2) {
            resVo.setTopTen(data.stream()
                    .sorted(Comparator.comparing(ReverseOrderLoadsDayResVo::getWorkLoad).reversed())
                    .limit(10)
                    .collect(Collectors.toList()));
        }


        if (resVo.getTopTen() != null && !resVo.getTopTen().isEmpty() && !reverseDetailList.isEmpty()) {
            BigDecimal multiply = resVo.getTopTen().get(0).getWorkLoad()
                    .multiply(new BigDecimal(reverseOrderList.size()))
                    .setScale(0, RoundingMode.UP);
            resVo.setTotal(multiply.intValue());
        }


        // 前十累加
        Map<String, List<ReverseOrderLoadsDayResVo>> groupAll = data.stream().collect(Collectors.groupingBy(ReverseOrderLoadsDayResVo::getGroupNo));
        List<ReverseOrderLoadsDayResVo> collect = groupAll.entrySet()
                .stream()
                .map(e -> {
                    ReverseOrderLoadsDayResVo r = new ReverseOrderLoadsDayResVo();
                    r.setGroupNo(e.getKey());
                    r.setGroupName(groupMap.get(e.getKey()).getName());
                    r.setWorkLoad(e.getValue().stream().map(ReverseOrderLoadsDayResVo::getWorkLoad).reduce(BigDecimal.ZERO, BigDecimal::add));
                    return r;
                })
                .sorted(Comparator.comparing(ReverseOrderLoadsDayResVo::getWorkLoad).reversed())
                .limit(10).collect(Collectors.toList());

        resVo.setTopTen(collect);


        ReverseOrder reverseOrder = reverseOrderMapper.selectById(reqVo.getId());

        resVo.setReverseOrderId(reverseOrder.getId());
        if (resVo.getTopTen() != null && !resVo.getTopTen().isEmpty() && !reverseDetailList.isEmpty()) {
            // 获取推荐的包数
            BigDecimal multiply = resVo.getTopTen().get(0).getWorkLoad().setScale(0, RoundingMode.UP);
            resVo.setTotal(multiply.intValue());

            // 查如果是该推荐包，是否有溢出的
            if(resVo.getTotal().equals(0)){
                resVo.setTotal(1);
            }
        }

        resVo.setRealSplitTotal(reverseOrder.getSplitNum());

        Integer count = reverseOrderMapper.lambdaQuery().eq(ReverseOrder::getParentId, reverseOrder.getId()).count();
        resVo.setRealTotal(count);

        return resVo;
    }


    @Transactional
    public void moveAps(BaseIdReqVo reqVo) {

        ReverseOrder reverseOrder = reverseOrderMapper.lambdaQuery()
                .isNull(ReverseOrder::getParentId)
                .eq(ReverseOrder::getOrderId, reqVo.getId())
                .one();
        Order order = orderMapper.selectById(reverseOrder.getOrderId());
        order.setOrderStatus(3);

        if (order.getOrderType() == 1 && order.getCustomerId() == null) {
            throw SyExceptionUtils.e("没有绑定客户信息!");
        }


        // 查询当前倒排状态是否已移入
        if (reverseOrder.getMoveFlag().equals(2)) {
            throw SyExceptionUtils.e("已经移入排产了");
        }

        // 该订单
        Integer count = apsOrderMapper.selectCount(Wrappers.<ApsOrder>lambdaQuery().eq(ApsOrder::getOrderId, reverseOrder.getOrderId()));
        if (count > 0) {
            throw SyExceptionUtils.e("已经移入排产了");
        }

        List<ReverseOrder> children = reverseOrderMapper.selectList(Wrappers.<ReverseOrder>lambdaQuery().eq(ReverseOrder::getParentId, reverseOrder.getId()));
        LambdaQueryWrapper<ApsOrder> wrapper1 = Wrappers.lambdaQuery();
        wrapper1.orderByDesc(ApsOrder::getSeq);
        wrapper1.last("limit 1");


        for (ReverseOrder e : children) {
            ApsOrder aps = new ApsOrder();
            aps.setOrderId(e.getOrderId());
            aps.setReverseId(e.getId());
            aps.setOrderCode(order.getOrderCode());
            aps.setConstructNo(order.getConstructNo());
            aps.setOrderQty(e.getOrderQty());
            aps.setFinishQty(0);
            aps.setOrderStatus(1);
            aps.setOrderType(order.getOrderType());
            aps.setSeq(e.getSplitNum());


            aps.setMaterCode(order.getMaterCode());
            aps.setMaterName(order.getMaterName());
            aps.setCustomerId(order.getCustomerId());
            if (order.getCustomerId() != null) {
                Customer customer = customerMapper.selectById(order.getCustomerId());
                if (customer == null) {
                    throw SyExceptionUtils.e("没有找到客户信息!");
                }
                aps.setCustomerCode(customer.getMyCode());
                aps.setCustomerName(customer.getName());
                aps.setCustomerPriority(customer.getPriority());
                aps.setCustomerWeight(customer.getWeight());
            }


            aps.setOrderPriority(order.getOrderPriority());
            aps.setOrderWeight(order.getOrderWeight());

            aps.setDeliveryDate(e.getDeliveryDate());
            aps.setLocked(1);

            apsOrderMapper.insert(aps);
        }

        reverseOrder.setMoveFlag(2);
        reverseOrderMapper.updateById(reverseOrder);

        // 查询order表中seq最大的加一
        List<Integer> list = Arrays.asList(1, 3, 4);
        if(list.contains(order.getOrderType())){
            Order maxOrder = orderMapper.selectOne(Wrappers.<Order>lambdaQuery().in(Order::getOrderStatus, 3, 4, 5).orderByDesc(Order::getSeq).last("limit 1"));
            int max = 1;
            if (maxOrder != null) {
                max = maxOrder.getSeq() + 1;
            }
            order.setSeq(max);
            orderMapper.updateById(order);
        }

        // TODO 部署43环境取消注释
        /*try {
            NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
            List<OrderBom> orderBomLanList = orderBomMapper.lambdaQuery().eq(OrderBom::getOrderId, order.getId()).eq(OrderBom::getMaterType, "Platepart").list();
            nestRule.partAdd(orderBomLanList);
        } catch (Exception e) {
            log.info("零件图纸同步失败：{}", e.getMessage());
        }*/

    }

    public BaseListResVo<ReverseOrderLoadsDetailResVo> loadsDetail(ReverseOrderLoadsDetailReqVo reqVo) {

        List<ReverseOrder> reverseOrderList = reverseOrderMapper.selectList(Wrappers.<ReverseOrder>lambdaQuery().eq(ReverseOrder::getParentId, reqVo.getId()));

        List<Integer> reverseOrderIds = reverseOrderList.stream().map(BaseEntity::getId).collect(Collectors.toList());

        LambdaQueryWrapper<ReverseDetail> wrapper = Wrappers.lambdaQuery();
        wrapper.in(ReverseDetail::getReverseOrderId, reverseOrderIds);
        wrapper.eq(ReverseDetail::getReverseDay, reqVo.getWorkDay());
        wrapper.eq(ReverseDetail::getGroupCode, reqVo.getGroupNo());
        wrapper.orderByDesc(ReverseDetail::getPlanStartSecond);
        List<ReverseDetail> reverseDetailList = reverseDetailMapper.selectList(wrapper);


        List<Integer> bomIds = reverseDetailList.stream().map(ReverseDetail::getBomId).distinct().collect(Collectors.toList());
        List<OrderBom> orderBomList = orderBomMapper.selectList(Wrappers.<OrderBom>lambdaQuery().in(OrderBom::getId, bomIds));
        Map<Integer, OrderBom> orderBomMap = orderBomList.stream().collect(Collectors.toMap(OrderBom::getId, Function.identity()));

        List<Integer> collect = reverseDetailList.stream().map(ReverseDetail::getPhaseId).distinct().collect(Collectors.toList());
        List<OrderPhase> orderPhaseList = orderPhaseMapper.selectBatchIds(collect);
        Map<Integer, OrderPhase> orderPhaseMap = orderPhaseList.stream().collect(Collectors.toMap(OrderPhase::getId, Function.identity()));

        List<ReverseOrderLoadsDetailResVo> list = new ArrayList<>(reverseDetailList.size());

        Map<Integer, ReverseOrder> reverseOrderMap = reverseOrderList.stream().collect(Collectors.toMap(ReverseOrder::getId, Function.identity()));
        for (ReverseDetail reverseDetail : reverseDetailList) {
            ReverseOrderLoadsDetailResVo vo = new ReverseOrderLoadsDetailResVo();
            OrderBom bom = orderBomMap.get(reverseDetail.getBomId());

            vo.setMaterCode(bom.getMaterCode());
            vo.setMaterName(bom.getMaterName());
            vo.setStartTime(reverseDetail.getReverseEndTime());
            vo.setEndTime(reverseDetail.getReverseStartTime());
            vo.setWorkCount(reverseDetail.getWorkCount());
            vo.setWorkAbility(reverseDetail.getWorkAbility());
            vo.setWorkTime(new BigDecimal(reverseDetail.getWorkTime()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
            vo.setGroupNo(reverseDetail.getGroupCode());

            vo.setAssemblyPath(bom.getAssemblyPath());
            vo.setWorkOrderCode(bom.getWorkOrderCode());
            vo.setPhase(orderPhaseMap.get(reverseDetail.getPhaseId()).getPhaseCode());
            vo.setFactoryNo("170");
            vo.setPlmId(bom.getPlmId());
            vo.setSaleCount(new BigDecimal(reverseOrderMap.get(reverseDetail.getReverseOrderId()).getOrderQty()));
            vo.setRealityTime(new BigDecimal(reverseDetail.getReverseDaySecond()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
            vo.setTotalStandardTime(vo.getRealityTime().multiply(vo.getSaleCount()));
            vo.setStandardTime(vo.getTotalStandardTime().divide(new BigDecimal(projectConfig.getDaySecond() / 60), 2, RoundingMode.HALF_UP));
            vo.setOrderCode(PkgUtils.gen(reverseDetail.getSplitNum()));
            vo.setWorkOrderNo("测试1");
            vo.setReverseOrderId(reverseDetail.getReverseOrderId());
            vo.setErpCode(bom.getErpCode());


            list.add(vo);
        }

        list.sort(Comparator.comparing(ReverseOrderLoadsDetailResVo::getStartTime));

        return new BaseListResVo<>(list);
    }

    public BaseListResVo<ReverseOrderBomResVo> bom(BaseIdReqVo reqVo) {
        ReverseOrder reverseOrder = reverseOrderMapper.selectById(reqVo.getId());

        List<OrderBom> orderBomList = orderBomMapper.selectList(Wrappers.<OrderBom>lambdaQuery().eq(OrderBom::getOrderId, reverseOrder.getOrderId()));

        return BaseListResVo.of(orderBomList, ReverseOrderBomResVo.class);
    }

    @Transactional
    public void unMoveAps(BaseIdReqVo reqVo) {

        ReverseOrder reverseOrder = reverseOrderMapper.selectById(reqVo.getId());

        List<ReverseOrder> reverseOrderList = reverseOrderMapper.selectList(Wrappers.<ReverseOrder>lambdaQuery().eq(ReverseOrder::getParentId, reqVo.getId()));


        apsOrderMapper.delete(Wrappers.<ApsOrder>lambdaQuery()
                .eq(ApsOrder::getOrderId, reverseOrder.getOrderId())
                .in(ApsOrder::getReverseId, reverseOrderList.stream().map(BaseEntity::getId).collect(Collectors.toList()))
                .isNull(ApsOrder::getBatchId)
        );
        reverseOrder.setMoveFlag(1);
        reverseOrderMapper.updateById(reverseOrder);

        Order order = orderMapper.selectById(reverseOrder.getOrderId());
        order.setOrderStatus(2);
        orderMapper.updateById(order);
    }

    public BaseListResVo<ReverseOrderLoadsDetailResVo> bomList(ReverseOrderBomListReqVo reqVo) {

        LambdaQueryWrapper<ReverseOrder> wrapper2 = Wrappers.lambdaQuery();
        wrapper2.eq(ReverseOrder::getParentId, reqVo.getReverseOrderId());
        wrapper2.eq(reqVo.getSubReverseOrderId() != null, ReverseOrder::getId, reqVo.getSubReverseOrderId());
        List<ReverseOrder> reverseOrderList = reverseOrderMapper.selectList(wrapper2);
        List<Integer> collect1 = reverseOrderList.stream().map(BaseEntity::getId).collect(Collectors.toList());


        LambdaQueryWrapper<ReverseDetail> wrapper = Wrappers.lambdaQuery();
        wrapper.in(ReverseDetail::getReverseOrderId, collect1);
        wrapper.eq(ReverseDetail::getBomId, reqVo.getBomId());
        wrapper.orderByDesc(ReverseDetail::getSplitNum);
        wrapper.orderByDesc(ReverseDetail::getReverseEndTime);
        List<ReverseDetail> reverseDetailList = reverseDetailMapper.selectList(wrapper);

        Map<Integer, ReverseDetail> collect2 = reverseDetailList.stream().collect(Collectors.toMap(ReverseDetail::getPhaseId, Function.identity(), (e1, e2) -> {
            if (e1.getReverseDay().isBefore(e2.getReverseDay())) {
                e1.setReverseStartTime(e2.getReverseStartTime());
            } else {
                e1.setReverseEndTime(e2.getReverseEndTime());
            }
            e1.setId(-1);
            return e1;
        }));

        reverseDetailList = collect2.values().stream().sorted(Comparator.comparing(ReverseDetail::getReverseEndTime).reversed()).collect(Collectors.toList());

        if (reverseDetailList.isEmpty()) {
            return new BaseListResVo<>(new ArrayList<>());
        }

        OrderBom bom = orderBomMapper.selectById(reqVo.getBomId());

        Map<Integer, ReverseOrder> reverseOrderMap = reverseOrderList.stream().collect(Collectors.toMap(ReverseOrder::getId, Function.identity()));
        List<Integer> collect = reverseDetailList.stream().map(ReverseDetail::getPhaseId).distinct().collect(Collectors.toList());
        List<OrderPhase> orderPhaseList = orderPhaseMapper.selectBatchIds(collect);


        Map<Integer, OrderPhase> orderPhaseMap = orderPhaseList.stream().collect(Collectors.toMap(OrderPhase::getId, Function.identity()));


        List<ReverseOrderLoadsDetailResVo> l = new ArrayList<>();
        for (ReverseDetail reverseDetail : reverseDetailList) {
            ReverseOrderLoadsDetailResVo vo = new ReverseOrderLoadsDetailResVo();
            vo.setMaterCode(bom.getMaterCode());

            vo.setMaterName(bom.getMaterName());
//            vo.setStartTime();
//            vo.setEndTime();
            vo.setEndTime(reverseDetail.getReverseStartTime());
            vo.setStartTime(reverseDetail.getReverseEndTime());
            vo.setWorkCount(reverseDetail.getWorkCount());
            vo.setWorkAbility(reverseDetail.getWorkAbility());
            vo.setWorkTime(new BigDecimal(reverseDetail.getWorkTime()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
            vo.setGroupNo(reverseDetail.getGroupCode());

            vo.setAssemblyPath(bom.getAssemblyPath());
            vo.setWorkOrderCode(bom.getWorkOrderCode());
            vo.setPhase(orderPhaseMap.get(reverseDetail.getPhaseId()).getPhaseCode());
            vo.setFactoryNo("170");
            vo.setPlmId(bom.getPlmId());
            vo.setSaleCount(new BigDecimal(reverseOrderMap.get(reverseDetail.getReverseOrderId()).getOrderQty()));
            vo.setRealityTime(new BigDecimal(reverseDetail.getReverseDaySecond()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
            vo.setTotalStandardTime(vo.getRealityTime().multiply(vo.getSaleCount()));
            vo.setStandardTime(vo.getTotalStandardTime().divide(new BigDecimal(projectConfig.getDaySecond() / 60), 2, RoundingMode.HALF_UP));
            vo.setOrderCode(PkgUtils.gen(reverseDetail.getSplitNum()));
            vo.setWorkOrderNo("测试1");
            vo.setReverseOrderId(reverseDetail.getReverseOrderId());
            vo.setErpCode(bom.getErpCode());
            l.add(vo);
        }

        return new BaseListResVo<>(l);
    }

    public BaseSelectResVo splitDetail(BaseIdReqVo reqVo) {
        List<ReverseOrder> reverseOrderList = reverseOrderMapper.selectList(Wrappers.<ReverseOrder>lambdaQuery().eq(ReverseOrder::getParentId, reqVo.getId()));

        List<BaseSelectItemResVo> collect = reverseOrderList.stream().map(e -> new BaseSelectItemResVo(PkgUtils.gen(e.getSplitNum()), e.getId())).collect(Collectors.toList());

        return BaseSelectResVo.of(collect);

    }

    @SneakyThrows
    @Transactional
    public ReverseOrderLoadsResVo autoSplit(Integer orderId) {

        Order order = orderMapper.selectById(orderId);

        if (Objects.isNull(order)) {
            throw SyExceptionUtils.e("订单不存在");
        }

        if(order.getOrderType().equals(2) && order.getOrderStatus() < 6){
            return mbdLoads(order);
        }

        LambdaQueryWrapper<ReverseOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ReverseOrder::getOrderId, order.getId());
        wrapper.isNull(ReverseOrder::getParentId);
        Integer ct = reverseOrderMapper.selectCount(wrapper);

        if (ct > 1) {
            throw SyExceptionUtils.e("存在多个拆包结果，无法智能拆包");
        }

        List<DictData> stationGroupBalancingRate = dictDataMapper.findByDictTypeCode("stationGroupBalancingRate");

        Map<String, DictData> groupBalancingRateMap = stationGroupBalancingRate.stream()
                .filter(e -> order.getMaterName().contains(e.getDictLabel().split("\\|")[1]))
                .collect(Collectors.toMap(e -> e.getDictLabel().split("\\|")[0], Function.identity()));

        Integer id = null;
        if (ct == 0) {
            // 1.先拆包
            ReverseOrderAddReqVo firstSplitReqVo = new ReverseOrderAddReqVo();
            firstSplitReqVo.setOrderId(order.getId());
            firstSplitReqVo.setSplitNum(1);
            firstSplitReqVo.setDeliveryDate(LocalDate.now().plusDays(30));
            Integer id1 = add(firstSplitReqVo, groupBalancingRateMap);

            // 2.再找到推荐包
            ReverseOrderLoadsReqVo tuijianReqVo = new ReverseOrderLoadsReqVo();
            tuijianReqVo.setId(id1);
            ReverseOrderLoadsResVo loads = loads(tuijianReqVo, 2, order);

            Integer total = autoAdd(order.getId(), groupBalancingRateMap);
            loads.setTotal(getTotal(total, order.getOrderQty()));

            ReverseTop top = new ReverseTop();
            top.setTopStr(jacksonObjectMapper.writeValueAsString(loads.getTopTen()));
            top.setOrderId(order.getId());
            reverseTopMapper.insert(top);

            // 3.清理上次的拆包数据
            deleteById(orderId);

            // 4.再跟据智能推荐包拆包
//            int packageCount = order.getOrderQty() / total;
//            if(order.getOrderQty() % total > 0){
//                packageCount++;
//            }

            ReverseOrderAddReqVo secondSplitReqVo = new ReverseOrderAddReqVo();
            secondSplitReqVo.setOrderId(order.getId());
            secondSplitReqVo.setSplitNum(total);
            secondSplitReqVo.setDeliveryDate(LocalDate.now().plusDays(30));
            id = add(secondSplitReqVo, groupBalancingRateMap);
        } else if (ct == 1) {
            // 查找存在的那一包
            ReverseOrder ro = reverseOrderMapper.selectList(wrapper).get(0);
            id = ro.getId();
        }

        // 返回该包的负荷
        ReverseOrderLoadsReqVo tuijianReqVo = new ReverseOrderLoadsReqVo();
        tuijianReqVo.setId(id);


        ReverseOrderLoadsResVo loads = loads(tuijianReqVo, 1, order);
//        Integer total = autoAdd(order.getId());

        loads.setOrderStatus(order.getOrderStatus());
//        loads.setTotal(total);
        // 读第一包的数量
        ReverseOrder ro = reverseOrderMapper.lambdaQuery().eq(ReverseOrder::getOrderId, order.getId()).isNotNull(ReverseOrder::getParentId).orderByAsc(ReverseOrder::getSplitNum).last("limit 1").one();
        loads.setRealSplitTotal(ro.getOrderQty());
        loads.setTopTen(mbdLoads(order).getTopTen());


        if (CollUtil.isNotEmpty(loads.getTopTen())) {
//            loads.setTotal(loads.getTopTen().get(0).getWorkLoad().setScale(0, RoundingMode.UP).intValue());
            loads.setTotal(getTotal(loads.getTopTen().get(0).getWorkLoad().setScale(0, RoundingMode.UP).intValue(), order.getOrderQty()));

        }
        return loads;
    }

    public ReverseOrderLoadsResVo mbdLoads(Order order) {

        LocalDate localDate = LocalDate.now().plusDays(30);

        int split = 1;

//        LambdaQueryWrapper<ReverseOrder> wrapper = Wrappers.lambdaQuery();
//        wrapper.eq(ReverseOrder::getOrderId, order.getId());
//        wrapper.eq(ReverseOrder::getSplitNum, split);
//        wrapper.isNull(ReverseOrder::getParentId);
//        ReverseOrder currentReverseOrder = reverseOrderMapper.selectOne(wrapper);
//        if (currentReverseOrder != null) {
//            throw SyExceptionUtils.e("该订单已经拆分过了");
//        }

        ReverseOrder root = new ReverseOrder();
        root.setOrderId(order.getId());
        root.setSplitNum(split);
        root.setDeliveryDate(localDate);
        root.setOrderQty(order.getOrderQty());
        root.setMoveFlag(1);
        root.setOrderCode(order.getOrderCode());
        root.setId(1);
//        reverseOrderMapper.insert(root);


        List<ReverseOrder> children = new ArrayList<>();
        ReverseOrder orderSplit1 = new ReverseOrder();
        orderSplit1.setId(2);
        orderSplit1.setOrderId(order.getId());
        orderSplit1.setParentId(root.getId());
        orderSplit1.setSplitNum(1);
        orderSplit1.setOrderQty(order.getOrderQty());
        orderSplit1.setDeliveryDate(localDate);
        orderSplit1.setMoveFlag(1);
        orderSplit1.setOrderDateTime(LocalDateTime.of(localDate, LocalTime.MIN));
        children.add(orderSplit1);

//
//        int div = order.getOrderQty() / reqVo.getSplitNum();
//        if(order.getOrderQty() % reqVo.getSplitNum() > 0){
//            div++;
//        }
//        int mod = order.getOrderQty() % reqVo.getSplitNum();
//        for (int i = 0; i < div; i++) {
//            ReverseOrder orderSplit1 = new ReverseOrder();
//            orderSplit1.setOrderId(reqVo.getId());
//            orderSplit1.setParentId(root.getId());
//            orderSplit1.setSplitNum(i + 1);
//            int currentQty = reqVo.getSplitNum();
//            if (mod > 0 && i == (div - 1)) {
//                currentQty = mod;
//            }
//            orderSplit1.setOrderQty(currentQty);
//            orderSplit1.setDeliveryDate(localDate.minusDays(reqVo.getSplitNum()).plusDays(orderSplit1.getSplitNum()));
//            orderSplit1.setMoveFlag(1);
//            children.add(orderSplit1);
//        }

//        reverseOrderMapper.insertBatchSomeColumn(children);
        List<DictData> stationGroupBalancingRate = dictDataMapper.findByDictTypeCode("stationGroupBalancingRate");

        Map<String, DictData> groupBalancingRateMap = stationGroupBalancingRate.stream()
                .filter(e -> order.getMaterName().contains(e.getDictLabel().split("\\|")[1]))
                .collect(Collectors.toMap(e -> e.getDictLabel().split("\\|")[0], Function.identity()));



        List<Station> stationList = stationMapper.selectList(null);
        List<Shift> shiftList = shiftMapper.lambdaQuery().list();
        Map<Integer, List<Shift>> collect1 = shiftList.stream().collect(Collectors.groupingBy(Shift::getShiftTypeId));

        Map<Integer, BigDecimal> workAbilityMap = new HashMap<>();
        for (Station station : stationList) {
            if(station.getShiftTypeId() == null){
                workAbilityMap.put(station.getId(), new BigDecimal(1));
                continue;
            }
            List<Shift> shifts = collect1.get(station.getShiftTypeId());
            if(shifts == null || shifts.isEmpty()){
                workAbilityMap.put(station.getId(), new BigDecimal(1));
                continue;
            }
            // shifts （总有效时长 / 总工作时间 ）
            BigDecimal validTimeResult = shifts.stream().map(e -> new BigDecimal(e.getValidTime())).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal workTimeResult = shifts.stream().map(e -> new BigDecimal(e.getTotalWorkTime())).reduce(BigDecimal.ZERO, BigDecimal::add);

            workAbilityMap.put(station.getId(), validTimeResult.divide(workTimeResult, 2, RoundingMode.HALF_UP));
        }

        List<Station> list = stationMapper.lambdaQuery().list();
        Map<Integer, Station> collect = list.stream().collect(Collectors.toMap(Station::getId, Function.identity()));

        Map<Integer, BigDecimal> workAbilityMap1 = new HashMap<>();
        for (Map.Entry<Integer, BigDecimal> entry : workAbilityMap.entrySet()) {
            Station station = collect.get(entry.getKey());
            if(station != null){
//                workAbilityMap1.put(stationGroup.getGroupId(), new BigDecimal(1));
//            } else {
                workAbilityMap1.put(station.getGroupId(), entry.getValue());
            }
        }

        // 倒序排产
        Map<ReverseOrder, List<ReverseDetail>> reverseOrderListMap = reverseAllSchedulingMbd(order, root, children, groupBalancingRateMap, workAbilityMap1);

        root.setPlanStartDateTime(children.stream().min(Comparator.comparing(ReverseOrder::getPlanStartDateTime)).orElseGet(ReverseOrder::new).getPlanStartDateTime());
        root.setPlanEndDateTime(children.stream().max(Comparator.comparing(ReverseOrder::getPlanEndDateTime)).orElseGet(ReverseOrder::new).getPlanEndDateTime());

        ReverseOrderLoadsResVo reverseOrderLoadsResVo = loadsMbd(reverseOrderListMap, root);

        List<ReverseOrder> reverseOrderList = reverseOrderMapper.lambdaQuery().eq(ReverseOrder::getOrderId, order.getId()).isNotNull(ReverseOrder::getParentId).list();

        if(CollUtil.isNotEmpty(reverseOrderList)){
            reverseOrderLoadsResVo.setRealTotal(reverseOrderList.size());
            reverseOrderLoadsResVo.setRealSplitTotal(reverseOrderList.get(0).getOrderQty());
        } else {
            reverseOrderLoadsResVo.setRealTotal(0);
            reverseOrderLoadsResVo.setRealSplitTotal(0);
        }

        if(reverseOrderLoadsResVo.getTotal() != null && reverseOrderLoadsResVo.getTotal() != 0){
            int i = order.getOrderQty() / reverseOrderLoadsResVo.getTotal();
            if(order.getOrderQty() % reverseOrderLoadsResVo.getTotal() > 0){
                i++;
            }
            reverseOrderLoadsResVo.setRealTotal(i);
        }

        return reverseOrderLoadsResVo;
    }

    @SneakyThrows
    public ReverseOrderLoadsResVo loadsMbd(Map<ReverseOrder, List<ReverseDetail>> reverseOrderListMap, ReverseOrder root) {
//        List<ReverseOrder> reverseOrderList = reverseOrderMapper.selectList(Wrappers.<ReverseOrder>lambdaQuery().eq(ReverseOrder::getParentId, reqVo.getId()));

        List<ReverseOrder> reverseOrderList = new ArrayList<>(reverseOrderListMap.keySet());

//        List<Integer> reverseOrderIds = reverseOrderList.stream().map(BaseEntity::getId).collect(Collectors.toList());
//        List<ReverseDetail> reverseDetailList = reverseDetailMapper.selectList(Wrappers.<ReverseDetail>lambdaQuery().in(ReverseDetail::getReverseOrderId, reverseOrderIds));
        List<ReverseDetail> reverseDetailList = reverseOrderListMap.values().stream().flatMap(List::stream).collect(Collectors.toList());


        Integer daySecond = projectConfig.getDaySecond();
        Map<Integer, ReverseOrder> reverseOrderMap = reverseOrderList.stream().collect(Collectors.toMap(ReverseOrder::getId, Function.identity()));

        for (ReverseDetail reverseDetail : reverseDetailList) {
            Integer orderQty = reverseOrderMap.get(reverseDetail.getReverseOrderId()).getOrderQty();
            reverseDetail.setReverseDaySecond(reverseDetail.getReverseDaySecond() * orderQty);
        }

        List<Group> groups = groupMapper.selectList(Wrappers.<Group>lambdaQuery().eq(Group::getType, 2));
        Map<String, Group> groupMap = groups.stream().collect(Collectors.toMap(Group::getMyCode, Function.identity(), (e1, e2) -> e1));
        List<Integer> groupIds = groups.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<Station> stations = stationMapper.lambdaQuery().in(Station::getGroupId, groupIds).list();
        Map<Integer, Long> stationGroupCountMap = stations.stream().collect(Collectors.groupingBy(Station::getGroupId, Collectors.counting()));

        List<ReverseOrderLoadsDayResVo> data = reverseDetailList.stream().collect(
                        Collectors.groupingBy(
                                ReverseDetail::getReverseDay,
                                Collectors.groupingBy(
                                        ReverseDetail::getGroupCode, Collectors.summingInt(ReverseDetail::getReverseDaySecond)
                                )
                        )
                )
                .entrySet().stream().flatMap(e ->
                        e.getValue()
                                .entrySet()
                                .stream()
                                .map(ee -> {
                                    ReverseOrderLoadsDayResVo r = new ReverseOrderLoadsDayResVo();
                                    r.setWorkDay(e.getKey());
                                    r.setGroupNo(ee.getKey());
                                    if (groupMap.get(ee.getKey()) != null) {
                                        r.setGroupName(groupMap.get(ee.getKey()).getName());
                                    }
                                    Long l = stationGroupCountMap.get(groupMap.get(ee.getKey()).getId());
                                    if(l == null){
                                        throw SyExceptionUtils.e("没有找到工作组[{}],请检查工位是否配置正确", ee.getKey());
                                    }

                                    r.setWorkLoad(new BigDecimal(ee.getValue())
                                            .divide(new BigDecimal(daySecond), 5, RoundingMode.HALF_UP)
                                            .divide(new BigDecimal(l), 4, RoundingMode.HALF_UP));
                                    return r;
                                })
                                .sorted(Comparator.comparing(ReverseOrderLoadsDayResVo::getWorkLoad).reversed())
                                .limit(10)
                ).collect(Collectors.toList());


        ReverseOrderLoadsResVo resVo = new ReverseOrderLoadsResVo();
        resVo.setData(data);

        int type = 2;
        if (type == 1) {

            ReverseTop top = reverseTopMapper.selectOne(Wrappers.<ReverseTop>lambdaQuery().eq(ReverseTop::getOrderId, root.getOrderId()));
            List<ReverseOrderLoadsDayResVo> reverseOrderLoadsDayResVos = new ArrayList<>();
            if (top != null) {
                reverseOrderLoadsDayResVos = jacksonObjectMapper.readValue(top.getTopStr(), new TypeReference<ArrayList<ReverseOrderLoadsDayResVo>>() {
                });
            }
            resVo.setTopTen(reverseOrderLoadsDayResVos);

        } else if (type == 2) {
            resVo.setTopTen(data.stream()
                    .sorted(Comparator.comparing(ReverseOrderLoadsDayResVo::getWorkLoad).reversed())
                    .limit(10)
                    .collect(Collectors.toList()));
        }


        if (resVo.getTopTen() != null && !resVo.getTopTen().isEmpty() && !reverseDetailList.isEmpty()) {
            BigDecimal multiply = resVo.getTopTen().get(0).getWorkLoad()
                    .multiply(new BigDecimal(reverseOrderList.size()))
                    .setScale(0, RoundingMode.UP);
            resVo.setTotal(multiply.intValue());
        }


        // 前十累加
        Map<String, List<ReverseOrderLoadsDayResVo>> groupAll = data.stream().collect(Collectors.groupingBy(ReverseOrderLoadsDayResVo::getGroupNo));
        List<ReverseOrderLoadsDayResVo> collect = groupAll.entrySet()
                .stream()
                .map(e -> {
                    ReverseOrderLoadsDayResVo r = new ReverseOrderLoadsDayResVo();
                    r.setGroupNo(e.getKey());
                    r.setGroupName(groupMap.get(e.getKey()).getName());
                    r.setWorkLoad(e.getValue().stream().map(ReverseOrderLoadsDayResVo::getWorkLoad).reduce(BigDecimal.ZERO, BigDecimal::add));
                    return r;
                })
                .sorted(Comparator.comparing(ReverseOrderLoadsDayResVo::getWorkLoad).reversed())
                .limit(10).collect(Collectors.toList());

        resVo.setTopTen(collect);



        resVo.setReverseOrderId(root.getId());
        if (resVo.getTopTen() != null && !resVo.getTopTen().isEmpty() && !reverseDetailList.isEmpty()) {
            // 获取推荐的包数
            BigDecimal multiply = resVo.getTopTen().get(0).getWorkLoad().setScale(0, RoundingMode.UP);
            resVo.setTotal(multiply.intValue());

            // 查如果是该推荐包，是否有溢出的
            if(resVo.getTotal().equals(0)){
                resVo.setTotal(1);
            }
        }

        resVo.setRealSplitTotal(1);

        resVo.setRealTotal(root.getSplitNum());

        return resVo;
    }

    public Map<ReverseOrder, List<ReverseDetail>> reverseAllSchedulingMbd(Order order, ReverseOrder root, List<ReverseOrder> children, Map<String, DictData> groupBalancingRateMap, Map<Integer, BigDecimal> workAbilityMap) {

        // 构建缓存数据
        ReverseFactoryCache factoryCache = createFactoryCache(order);

        Map<ReverseOrder, List<ReverseDetail>> map = new HashMap<>();

        int idIndex = 10;
        // 对每个分包进行排产
        for (ReverseOrder child : children) {
            ReverseOrderCache orderCache = createOrderCache(order, root, child);
            List<ReverseDetail> reverseDetails = reverseAllSchedulingMbd(factoryCache, orderCache, groupBalancingRateMap, workAbilityMap);

            // 把分钟按天分隔
            List<ReverseDetail> dayDetails = dayDetails(child, reverseDetails);

            child.setPlanEndDateTime(dayDetails.stream().max(Comparator.comparing(ReverseDetail::getReverseStartTime)).orElseGet(ReverseDetail::new).getReverseStartTime());
            child.setPlanStartDateTime(dayDetails.stream().min(Comparator.comparing(ReverseDetail::getReverseEndTime)).orElseGet(ReverseDetail::new).getReverseEndTime());

            for (ReverseDetail dayDetail : dayDetails) {
                dayDetail.setId(idIndex++);
            }

            map.put(child, dayDetails);
        }
        return map;
    }

    private List<ReverseDetail> reverseAllSchedulingMbd(ReverseFactoryCache factoryCache, ReverseOrderCache orderCache, Map<String, DictData> groupBalancingRateMap, Map<Integer, BigDecimal> workAbilityMap) {
        DictData dictData = new DictData();
        dictData.setDictValue("1");


        orderCache.getOrderBomList().sort(Comparator.comparing(OrderBom::getLevel));
        List<OrderBom> orderBomList = orderCache.getOrderBomList();

        Map<Integer, OrderBom> orderBomIdMap = orderBomList.stream().collect(Collectors.toMap(OrderBom::getId, Function.identity()));
        for (OrderPhase orderPhase : orderCache.getOrderPhaseList()) {
            if (orderPhase.getPhaseSeq() == null) {
                throw SyExceptionUtils.e("没有配置工序顺序");
            }

            if(!StringUtils.hasText(orderPhase.getWorkGroupNumber())){
                throw SyExceptionUtils.e(orderPhase.getMaterName() + "没有配置工作组");
            }

            if(orderPhase.getWorkTime() == null){
                throw SyExceptionUtils.e(orderPhase.getMaterName() + "没有配置工时");
            }
        }

        Map<Integer, List<OrderPhase>> bomIdPhaseMap = orderCache.getOrderPhaseList()
                .stream()
                .sorted(Comparator.comparing(OrderPhase::getPhaseSeq))
                .collect(Collectors.groupingBy(OrderPhase::getBomId));

        Map<Integer, Map<Integer, ReverseDetail>> bomIdPhaseSeqMap = new LinkedHashMap<>();

        for (OrderBom orderBom : orderBomList) {
            List<OrderPhase> orderPhaseList = bomIdPhaseMap.get(orderBom.getId());
            if (orderPhaseList == null || orderPhaseList.isEmpty()) {
                continue;
            }

            // 反向计算工序时间
            int startSecond = 0;
            for (int i = orderPhaseList.size() - 1; i >= 0; i--) {
                // 是否是最开始的工序
                if (i == orderPhaseList.size() - 1) {
                    // 取父节点的
                    OrderBom parentBom = orderBomIdMap.get(orderBom.getPid());
                    if (parentBom != null) {
                        Map<Integer, ReverseDetail> map = bomIdPhaseSeqMap.get(parentBom.getId());

                        if (CollUtil.isEmpty(map)) {
                            throw SyExceptionUtils.e("零件[{}], 物料号[{}]没有找到父节点零件[{}], 物料号[{}]的工序", orderBom.getMaterName(), orderBom.getMaterCode(), parentBom.getMaterName(), parentBom.getMaterCode());
                        }

                        ReverseDetail reversePhase = map.get(1);
                        startSecond = reversePhase.getPlanEndSecond();
                    }

                } else {
                    // 取前一道工序
                    ReverseDetail reversePhase = bomIdPhaseSeqMap.get(orderPhaseList.get(i).getBomId()).get(orderPhaseList.get(i).getPhaseSeq() + 1);
                    startSecond = reversePhase.getPlanEndSecond();
                }

                ReverseDetail phase = new ReverseDetail();
                phase.setPhaseSeq(orderPhaseList.get(i).getPhaseSeq());
                phase.setPhaseId(orderPhaseList.get(i).getId());
                phase.setReverseOrderId(orderCache.getReverseOrder().getId());
                phase.setOrderId(orderCache.getReverseOrder().getOrderId());
                phase.setBomId(orderBom.getId());
                phase.setBomPid(orderBom.getPid());
                phase.setGroupCode(orderPhaseList.get(i).getWorkGroupNumber());
                phase.setPlanStartSecond(startSecond);
                phase.setLevel(orderBom.getLevel());

                bomIdPhaseSeqMap.computeIfAbsent(orderPhaseList.get(i).getBomId(), k -> new LinkedHashMap<>()).put(phase.getPhaseSeq(), phase);

                ReverseWorkCenter stationList = factoryCache.getWorkCenterMap().get(orderPhaseList.get(i).getWorkGroupNumber());
                if (stationList == null) {
                    throw SyExceptionUtils.e("零件[{}], 物料号[{}]没有找到工作组[{}],或者该工作组下没有工位", orderBom.getMaterName(), orderBom.getMaterCode(), orderPhaseList.get(i).getWorkGroupNumber());
                }

                phase.setStationGroupId(stationList.getStationGroupId());

                phase.setGroupId(stationList.getGroupId());

                // 取出这个工序的真实的工作秒数
                phase.setWorkCount(stationList.getGroupList().size());
                phase.setWorkAbility(stationList.getWorkAbility());
                phase.setWorkTime(orderPhaseList.get(i).getWorkTime());
                phase.setTotalCount(orderBomIdMap.get(orderBom.getId()).getTotalCount());

                phase.setSplitNum(orderCache.getReverseOrder().getSplitNum());

                int phaseTime = phase.getTotalCount()
                        .multiply(new BigDecimal(phase.getWorkTime()))//600
                        .multiply(new BigDecimal(groupBalancingRateMap.getOrDefault(phase.getGroupCode(), dictData).getDictValue())) //1
                        .divide(workAbilityMap.get(phase.getGroupId()), 0, RoundingMode.HALF_UP)
//                        .divide(phase.getWorkAbility(), 5, RoundingMode.UP)// 1
                        .setScale(0, RoundingMode.UP)
                        .intValue();

                phase.setProcessSecond(phaseTime);

                phase.setPlanEndSecond(phase.getPlanStartSecond() + phase.getProcessSecond());

            }

        }

        /*


        Map<Integer, OrderBom> orderBomIdMap = orderBomList.stream().collect(Collectors.toMap(OrderBom::getId, Function.identity()));
        Map<Integer, Map<Integer, ReverseDetail>> bomIdPhaseSeqMap = new LinkedHashMap<>();
        Map<String, List<Station>> groupNumberStationMap = new HashMap<>();
//        Map<String, Group> myCodeGroupMap = factoryCache.getGroupList().stream().collect(Collectors.toMap(Group::getMyCode, Function.identity()));
        if (!factoryCache.getGroupList().isEmpty()) {
            List<Group> groupList = factoryCache.getGroupList();
            Map<Integer, List<StationGroup>> stationGroupMap = factoryCache.getStationGroupList().stream().filter(e -> e.getDefaultGroup().equals(1)).collect(Collectors.groupingBy(StationGroup::getGroupId));
            Map<Integer, Station> stationMap = factoryCache.getStationList().stream().collect(Collectors.toMap(Station::getId, Function.identity()));
            for (Group group : groupList) {
                List<StationGroup> stationGroups = stationGroupMap.get(group.getId());
                if (stationGroups == null || stationGroups.isEmpty()) {
                    continue;
                }

                List<Station> stations = stationGroups.stream().map(e -> stationMap.get(e.getStationId())).collect(Collectors.toList());
                groupNumberStationMap.put(group.getMyCode(), stations);
            }
        }

        // 排序后的每个零件

        return bomIdPhaseSeqMap.values().stream().flatMap(entry -> entry.values().stream()).sorted(Comparator.comparing(ReverseDetail::getPlanStartSecond)).collect(Collectors.toList());

         */

        return bomIdPhaseSeqMap.values().stream().flatMap(entry -> entry.values().stream()).sorted(Comparator.comparing(ReverseDetail::getPlanStartSecond)).collect(Collectors.toList());
    }

    private Integer getTotal(Integer total, Integer orderQty) {
        if (total <= 0) {
            return 1;
        }

        int div = orderQty / total;
        int mod = orderQty % total;
        if(mod > 0){
            div++;
        }

        int splitNum = orderQty / div;
        if(orderQty % div > 0){
            splitNum++;
        }
        return splitNum;
    }


    public void deleteById(Integer id) {

//        ReverseOrder ro = reverseOrderMapper.selectById(id);
        reverseOrderMapper.deleteHard(id);
        reverseDetailMapper.deleteHard(id);

    }

    @Transactional
    public void autoEdit(ReverseOrderAutoEditReqVo reqVo) {

        Order order = orderMapper.selectById(reqVo.getId());

        if (order.getOrderStatus() > 2) {
            throw SyExceptionUtils.e("订单已移入排产，不允许拆单");
        }
        deleteById(reqVo.getId());

        LocalDate localDate = LocalDate.now().plusDays(30);


        if (reqVo.getSplitNum() == null || reqVo.getSplitNum() <= 0) {
            throw SyExceptionUtils.e("拆分数量必须大于0");
        }


        Integer total = reqVo.getItem().stream().map(ReverseOrderAutoEditDataReqVo::getTotal).reduce(0, Integer::sum);

        if (!total.equals(order.getOrderQty())) {
            throw SyExceptionUtils.e("明细架数订单数必须相同");
        }


        if (order.getOrderStatus().equals(1)) {
            order.setOrderStatus(2);
            orderMapper.updateById(order);
        }

        LambdaQueryWrapper<ReverseOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ReverseOrder::getOrderId, reqVo.getId());
        wrapper.eq(ReverseOrder::getSplitNum, reqVo.getSplitNum());
        wrapper.isNull(ReverseOrder::getParentId);
        ReverseOrder currentReverseOrder = reverseOrderMapper.selectOne(wrapper);
        if (currentReverseOrder != null) {
            throw SyExceptionUtils.e("该订单已经拆分过了");
        }

        ReverseOrder root = new ReverseOrder();
        root.setOrderId(reqVo.getId());
        root.setSplitNum(reqVo.getSplitNum());
        root.setDeliveryDate(localDate);
        root.setOrderQty(order.getOrderQty());
        root.setMoveFlag(1);
        root.setOrderCode(order.getOrderCode());
        reverseOrderMapper.insert(root);


        List<ReverseOrder> children = new ArrayList<>();
        for (int i = 0; i < reqVo.getItem().size(); i++) {
            if (reqVo.getItem().get(i).getTotal() < 0) {
                throw SyExceptionUtils.e("明细架数不能为负数!");
            }
            ReverseOrder orderSplit1 = new ReverseOrder();
            orderSplit1.setOrderId(reqVo.getId());
            orderSplit1.setParentId(root.getId());
            orderSplit1.setSplitNum(i + 1);
            orderSplit1.setOrderQty(reqVo.getItem().get(i).getTotal());
            orderSplit1.setDeliveryDate(reqVo.getItem().get(i).getStartDate());
            orderSplit1.setMoveFlag(1);
            orderSplit1.setOrderDateTime(LocalDateTime.of(reqVo.getItem().get(i).getStartDate(), LocalTime.MIN));
            children.add(orderSplit1);
        }

//
//        int div = order.getOrderQty() / reqVo.getSplitNum();
//        if(order.getOrderQty() % reqVo.getSplitNum() > 0){
//            div++;
//        }
//        int mod = order.getOrderQty() % reqVo.getSplitNum();
//        for (int i = 0; i < div; i++) {
//            ReverseOrder orderSplit1 = new ReverseOrder();
//            orderSplit1.setOrderId(reqVo.getId());
//            orderSplit1.setParentId(root.getId());
//            orderSplit1.setSplitNum(i + 1);
//            int currentQty = reqVo.getSplitNum();
//            if (mod > 0 && i == (div - 1)) {
//                currentQty = mod;
//            }
//            orderSplit1.setOrderQty(currentQty);
//            orderSplit1.setDeliveryDate(localDate.minusDays(reqVo.getSplitNum()).plusDays(orderSplit1.getSplitNum()));
//            orderSplit1.setMoveFlag(1);
//            children.add(orderSplit1);
//        }

        reverseOrderMapper.insertBatchSomeColumn(children);
        List<DictData> stationGroupBalancingRate = dictDataMapper.findByDictTypeCode("stationGroupBalancingRate");

        Map<String, DictData> groupBalancingRateMap = stationGroupBalancingRate.stream()
                .filter(e -> order.getMaterName().contains(e.getDictLabel().split("\\|")[1]))
                .collect(Collectors.toMap(e -> e.getDictLabel().split("\\|")[0], Function.identity()));
        // 倒序排产
        reverseAllScheduling(order, root, children, groupBalancingRateMap);

        root.setPlanStartDateTime(children.stream().min(Comparator.comparing(ReverseOrder::getPlanStartDateTime)).orElseGet(ReverseOrder::new).getPlanStartDateTime());
        root.setPlanEndDateTime(children.stream().max(Comparator.comparing(ReverseOrder::getPlanEndDateTime)).orElseGet(ReverseOrder::new).getPlanEndDateTime());
        reverseOrderMapper.updateById(root);



//        add(firstSplitReqVo);

    }

    public int autoAdd(Integer orderId, Map<String, DictData> groupBalancingRateMap) {

        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw SyExceptionUtils.e("没有找到该订单");
        }

        LocalDate deliveryDate = LocalDate.now().plusDays(30);

        ReverseFactoryCache factoryCache = createFactoryCache(order);

        Integer daySecond = projectConfig.getDaySecond();

        List<Group> groups = groupMapper.selectList(Wrappers.<Group>lambdaQuery().eq(Group::getType, 2));
        Map<String, Group> groupMap = groups.stream().collect(Collectors.toMap(Group::getMyCode, Function.identity(), (e1, e2) -> e1));
        List<Integer> groupIds = groups.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<Station> stations = stationMapper.lambdaQuery().in(Station::getGroupId, groupIds).list();
        Map<Integer, Long> stationGroupCountMap = stations.stream().collect(Collectors.groupingBy(Station::getGroupId, Collectors.counting()));


        for (int splitNum = 1; splitNum <= order.getOrderQty(); splitNum++) {

            LambdaQueryWrapper<ReverseOrder> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(ReverseOrder::getOrderId, order.getId());
            wrapper.eq(ReverseOrder::getSplitNum, splitNum);
            wrapper.isNull(ReverseOrder::getParentId);

            ReverseOrder root = new ReverseOrder();
            root.setOrderId(order.getId());
            root.setSplitNum(splitNum);
            root.setDeliveryDate(deliveryDate);
            root.setOrderQty(order.getOrderQty());
            root.setMoveFlag(1);
            root.setOrderCode(order.getOrderCode());


            List<ReverseOrder> children = new ArrayList<>();
            int mod = order.getOrderQty() % splitNum;
            for (int i = 0; i < splitNum; i++) {
                ReverseOrder orderSplit1 = new ReverseOrder();
                orderSplit1.setId(i);
                orderSplit1.setOrderId(order.getId());
                orderSplit1.setParentId(root.getId());
                orderSplit1.setSplitNum(i + 1);
                int currentQty = order.getOrderQty() / splitNum + (splitNum - mod > i ? 0 : 1);
                orderSplit1.setOrderQty(currentQty);
                orderSplit1.setDeliveryDate(deliveryDate.minusDays(splitNum).plusDays(orderSplit1.getSplitNum()));
                orderSplit1.setMoveFlag(1);
                children.add(orderSplit1);
            }

            // 倒序排产

            // 对每个分包进行排产
            List<ReverseDetail> reverseDetailList = new ArrayList<>();
            for (ReverseOrder child : children) {
                ReverseOrderCache orderCache = createOrderCache(order, root, child);
                List<ReverseDetail> reverseDetails = reverseAllScheduling(factoryCache, orderCache, groupBalancingRateMap);

                // 把分钟按天分隔
                List<ReverseDetail> dayDetails = dayDetails(child, reverseDetails);
                reverseDetailList.addAll(dayDetails);

                child.setPlanEndDateTime(dayDetails.stream().max(Comparator.comparing(ReverseDetail::getReverseStartTime)).orElseGet(ReverseDetail::new).getReverseStartTime());
                child.setPlanStartDateTime(dayDetails.stream().min(Comparator.comparing(ReverseDetail::getReverseEndTime)).orElseGet(ReverseDetail::new).getReverseEndTime());
            }

            root.setPlanStartDateTime(children.stream().min(Comparator.comparing(ReverseOrder::getPlanStartDateTime)).orElseGet(ReverseOrder::new).getPlanStartDateTime());
            root.setPlanEndDateTime(children.stream().max(Comparator.comparing(ReverseOrder::getPlanEndDateTime)).orElseGet(ReverseOrder::new).getPlanEndDateTime());

            Map<Integer, ReverseOrder> reverseOrderMap = children.stream().collect(Collectors.toMap(ReverseOrder::getId, Function.identity()));

            for (ReverseDetail reverseDetail : reverseDetailList) {
                Integer orderQty = reverseOrderMap.get(reverseDetail.getReverseOrderId()).getOrderQty();
                reverseDetail.setReverseDaySecond(reverseDetail.getReverseDaySecond() * orderQty);
            }


            List<ReverseOrderLoadsDayResVo> data = reverseDetailList.stream().collect(Collectors.groupingBy(ReverseDetail::getReverseDay, Collectors.groupingBy(ReverseDetail::getGroupCode, Collectors.summingInt(ReverseDetail::getReverseDaySecond)))).entrySet().stream().flatMap(e -> e.getValue().entrySet().stream().map(ee -> {
                ReverseOrderLoadsDayResVo r = new ReverseOrderLoadsDayResVo();
                r.setWorkDay(e.getKey());
                r.setGroupNo(ee.getKey());
                if (groupMap.get(ee.getKey()) != null) {
                    r.setGroupName(groupMap.get(ee.getKey()).getName());
                }
                Long l = stationGroupCountMap.get(groupMap.get(ee.getKey()).getId());

                r.setWorkLoad(new BigDecimal(ee.getValue()).divide(new BigDecimal(daySecond), 5, RoundingMode.HALF_UP).divide(new BigDecimal(l), 2, RoundingMode.HALF_UP));
                return r;
            }).sorted(Comparator.comparing(ReverseOrderLoadsDayResVo::getWorkLoad).reversed()).limit(10)).collect(Collectors.toList());

            List<ReverseOrderLoadsDayResVo> collect = data.stream().filter(e -> e.getWorkLoad().compareTo(new BigDecimal(1)) > 0).collect(Collectors.toList());
            if (collect.isEmpty()) {
                return splitNum;
            }
        }
        throw SyExceptionUtils.e("当前工位的数量无法拆包，请调整并行数量或者工位数");
    }

    public BaseListResVo<ReverseOrderSplitPreviewResVo> splitPreview(ReverseOrderSplitPreviewReqVo reqVo) {

        int div = reqVo.getTotalCount() / reqVo.getSplitCount();
        if(reqVo.getTotalCount() % reqVo.getSplitCount() > 0){
            div++;
        }

        int mod = reqVo.getTotalCount() % reqVo.getSplitCount();
        LocalDate localDate = LocalDate.now().plusMonths(1);

        List<ReverseOrderSplitPreviewResVo > l = new ArrayList<>();
        for (int i = 0; i < div; i++) {

            int currentQty = reqVo.getSplitCount();
            if (mod > 0 && i == (div - 1)) {
                currentQty = mod;
            }

            ReverseOrderSplitPreviewResVo r = new ReverseOrderSplitPreviewResVo();
            r.setPkgCode(PkgUtils.gen(i+1));
            r.setTotal(currentQty);
            r.setStartDate(localDate.plusDays(i));

            l.add(r);
        }
        return new BaseListResVo<>(l);
    }

    @Transactional
    public void autoEditMbd(ReverseOrderAutoEditReqVo reqVo) {
        Order order = orderMapper.selectById(reqVo.getId());
        if (order.getOrderStatus() >= 6) {
            throw SyExceptionUtils.e("订单已发布，不允许拆单");
        }

        apsOrderMapper.deleteOrderId(reqVo.getId());
        apsWorkOrderMapper.deleteOrderId(reqVo.getId());
        apsWorkDetailMapper.deleteOrderId(reqVo.getId());
        apsDetailWeekdayMapper.deleteOrderId(reqVo.getId());
        reverseOrderMapper.deleteHard(reqVo.getId());
        reverseDetailMapper.deleteHard(reqVo.getId());

        LocalDate localDate = LocalDate.now().plusDays(30);

        if (reqVo.getSplitNum() == null || reqVo.getSplitNum() <= 0) {
            throw SyExceptionUtils.e("拆分数量必须大于0");
        }

        Integer total = reqVo.getItem().stream().map(ReverseOrderAutoEditDataReqVo::getTotal).reduce(0, Integer::sum);

        if (!total.equals(order.getOrderQty())) {
            throw SyExceptionUtils.e("明细架数订单数必须相同");
        }

        if (order.getOrderStatus().equals(1)) {
            order.setOrderStatus(3);
            orderMapper.updateById(order);
        } else if (order.getOrderStatus() >= 2){
            order.setOrderStatus(3);
            orderMapper.updateById(order);
        }

        LambdaQueryWrapper<ReverseOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ReverseOrder::getOrderId, reqVo.getId());
        wrapper.eq(ReverseOrder::getSplitNum, reqVo.getSplitNum());
        wrapper.isNull(ReverseOrder::getParentId);
        ReverseOrder currentReverseOrder = reverseOrderMapper.selectOne(wrapper);
        if (currentReverseOrder != null) {
            throw SyExceptionUtils.e("该订单已经拆分过了");
        }

        ReverseOrder root = new ReverseOrder();
        root.setOrderId(reqVo.getId());
        root.setSplitNum(reqVo.getSplitNum());
        root.setDeliveryDate(localDate);
        root.setOrderQty(order.getOrderQty());
        root.setMoveFlag(1);
        root.setOrderCode(order.getOrderCode());
        reverseOrderMapper.insert(root);

        List<ReverseOrder> children = new ArrayList<>();
        for (int i = 0; i < reqVo.getItem().size(); i++) {
            if (reqVo.getItem().get(i).getTotal() < 0) {
                throw SyExceptionUtils.e("明细架数不能为负数!");
            }
            ReverseOrder orderSplit1 = new ReverseOrder();
            orderSplit1.setOrderId(reqVo.getId());
            orderSplit1.setParentId(root.getId());
            orderSplit1.setSplitNum(i + 1);
            orderSplit1.setOrderQty(reqVo.getItem().get(i).getTotal());
            orderSplit1.setDeliveryDate(reqVo.getItem().get(i).getStartDate());
            orderSplit1.setMoveFlag(1);
            orderSplit1.setOrderDateTime(LocalDateTime.of(reqVo.getItem().get(i).getStartDate(), LocalTime.MIN));
            children.add(orderSplit1);
        }

        reverseOrderMapper.insertBatchSomeColumn(children);
        List<DictData> stationGroupBalancingRate = dictDataMapper.findByDictTypeCode("stationGroupBalancingRate");

        Map<String, DictData> groupBalancingRateMap = stationGroupBalancingRate.stream()
                .filter(e -> order.getMaterName().contains(e.getDictLabel().split("\\|")[1]))
                .collect(Collectors.toMap(e -> e.getDictLabel().split("\\|")[0], Function.identity()));
        // 倒序排产
        reverseAllScheduling(order, root, children, groupBalancingRateMap);

        root.setPlanStartDateTime(children.stream().min(Comparator.comparing(ReverseOrder::getPlanStartDateTime)).orElseGet(ReverseOrder::new).getPlanStartDateTime());
        root.setPlanEndDateTime(children.stream().max(Comparator.comparing(ReverseOrder::getPlanEndDateTime)).orElseGet(ReverseOrder::new).getPlanEndDateTime());
        reverseOrderMapper.updateById(root);


        BaseIdReqVo baseIdReqVo = new BaseIdReqVo();
        baseIdReqVo.setId(reqVo.getId());
        this.moveAps(baseIdReqVo);

    }
}
